fix(dav): ignore calendars in the trash bin for free-busy and user status - #62667
fix(dav): ignore calendars in the trash bin for free-busy and user status#62667ndo84bw wants to merge 2 commits into
Conversation
Assisted-by: ClaudeCode:claude-opus-5 Signed-off-by: Nico Donath <ndo84bw@gmx.de>
Assisted-by: ClaudeCode:claude-opus-5 Signed-off-by: Nico Donath <ndo84bw@gmx.de>
SebastianKrupinski
left a comment
There was a problem hiding this comment.
Hi,
I am going to block this PR.
calendarQuery() and search() are used by other parts of our code to find objects both in and outside of the trash bin.
Not sure doing this here is the best idea
|
Hi @SebastianKrupinski , The Trashbin listing runs via a different path with a method of the same name. ( I’ve seen this in the following consumers:
Note RFC-6638 9.1: When deleting the calendar, we could set this and would have already handled the two prominent queries. However, then I wouldn’t know the previous state during restoration. In addition to these two consumers, I’ve identified the following (not yet tested; there may be a few too many):
I mean, I read in the Contributor Guidelines that a review shouldn't take any more time than the value the patch adds. This would be one of those cases for me. Issue #32989 describes a problem that I would call an edge case. And on top of that, it resolves itself automatically after a certain amount of time. My suggestion: Do you agree with my suggestion, or do you have another solution that would take less time? If not, I’ll close my PR. I don’t think it’s reasonable. |
Summary
If a calendar holds events that count as busy and you delete that calendar, the events in it are still evaluated for free/busy lookups and for the automatic user status.
The reason is that deleting a calendar only marks the calendar as deleted, not the events inside it. Trashed calendars are hidden from clients purely through their resourcetype, but Sabre's free/busy code picks the calendars to query by PHP class, so that masking never applies there.
This patch filters out calendars in the trash bin in both cases.
What the fix does
Calendar::calendarQuery()returns[]when the calendar is in the trash bin. This covers the scheduling outbox free/busy request (Sabre'sSchedule\Plugin::getFreeBusyForEmail),OCA\DAV\CalDAV\Schedule\Plugin::isAvailableAtTime(room and resource auto-reply),OC\Calendar\Manager::checkAvailability, and thecalendar-queryandfree-busy-queryREPORTs.CalendarImpl::search()returns[]when the calendar is in the trash bin. This coversManager::searchForPrincipal()andManager::search(), and with themStatusService(the "In a meeting" user status) andUpcomingEventsService(dashboard and upcoming events).What the fix does not touch
PROPFINDDepth:1 on a trashed calendar still lists its objects, andGETstill serves them with 200.PROPFINDon/public-calendars/<token>/still answers 207 and lists the object, while acalendar-queryREPORT on the same link now comes back empty.CalDavBackend::getCalendarObjectByUID()filtersco.deleted_atbut notc.deleted_at, so an incoming iTIP reply can still be applied to an event inside a trashed calendar. Skipping it would duplicate the event instead: Sabre would treat it as unknown and create a new copy in the default calendar, next to the old one in the trashed calendar.One consequence I could not verify:
scheduleLocalDeliveryauto-replies for rooms and resources based on the same availability query, so a room whose own calendar sits in the trash bin should now reply ACCEPTED instead of DECLINED, because the bookings in that calendar no longer count as busy. Reproducing this needs a room or resource principal, which only exists if an app provides one.Tests
Manual, live (docker dev container, NC 35.0.0 dev, PHP 8.5):
DELETEof the calendar still returnedFREEBUSY:20260729T100000Z/20260729T110000Z; with the fix the VFREEBUSY comes back empty. Restoring from the trash bin (MOVEtotrashbin/restore/file) still works, and the slot is busy again afterwards.calendar-queryREPORT on the trashed calendar: empty multistatus.GET /ocs/v2.php/apps/dav/api/v1/events/upcoming), A/B with and without theCalendarImplguard: without it the event from the trashed calendar appears, with it the list is empty.busywithmessage_id = meeting, so the calendar icon shows on the avatar; with the patchrevertUserStatus()restores the previousonlinestatus and the icon disappears. Two things to keep in mind when reproducing: the calendar status result is cached per user for 5 minutes (StatusService, where the cache lives depends onmemcache.local), and a manually set status suppresses events that started before it, otherwise the test comes out falsely negative.Unit tests:
CalendarTestcoverscalendarQuery()for a live, a trashed and a shared calendar (PublicCalendarTestinherits them)CalendarImplTestcoverssearch()for a trashed calendarphpunit --filter "CalendarTest|CalendarImplTest"- 143 tests greenChecklist
3. to review, feature component)stable32)AI (if applicable)